#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;

template <class T>
class BlockQueue
{
private:
    queue<T> q_;
    int capacity_;
    pthread_mutex_t mutex_;
    pthread_cond_t full_;
    pthread_cond_t empty_;
    bool isFull() { return q_.size() == capacity_; }
    bool isEmpty() { return q_.empty(); }

public:
    BlockQueue(int capacity)
        : capacity_(capacity)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&full_, nullptr);
        pthread_cond_init(&empty_, nullptr);
    }
    void push(T &t)
    {
        pthread_mutex_lock(&mutex_);
        while (isFull()) // 当队列满的时候，生产线程在full_条件下等待。
        {
            pthread_cond_wait(&full_, &mutex_); // 函数在线程阻塞的时候会自动释放锁，在线程被唤醒的时候会自动申请锁
        }
        q_.push(t);
        pthread_cond_signal(&empty_); // 生产者生产完数据，唤醒在empty_条件下等待的消费者
        pthread_mutex_unlock(&mutex_);
    }
    void pop(T &data) // 输出型参数
    {
        pthread_mutex_lock(&mutex_);
        while (isEmpty()) // 当队列空的时候，消费线程在empty_条件下等待。
        {
            pthread_cond_wait(&empty_, &mutex_); // 函数在线程阻塞的时候会自动释放锁，在线程被唤醒的时候会自动申请锁
        }
        data = q_.front();
        q_.pop();
        pthread_cond_signal(&full_); // 消费者消费完数据，唤醒在full_条件下等待的生产者
        pthread_mutex_unlock(&mutex_);
    }
};